#ifndef CONTAINER_H
#define CONTAINER_H
#include <exception>
using namespace std;
//Container template class declaration
template<class T> 
class Container_t{
public:
	Container_t();
	virtual ~Container_t() = 0;		
	int count() const;
	virtual T* find(T val);
	virtual bool insert(const T* elem) throw(exception);
	virtual bool append(const T* elem, const int index)throw(exception);
	virtual bool prepend(const T* elem, const int index)throw(exception);
	virtual T* remove(T val);
	virtual bool removeAndDelete(T val);
	virtual bool removeAll();
	virtual bool removeAndDeleteAll();
	//Just for testing
	void print();
protected:
	//must be provided in derived classes
	//in order to implement most of the functionality in base class
	virtual T* next() = 0;
	virtual T* prev() = 0;
	virtual void reset() = 0;
	virtual bool appendAction(const T* elem, const int index) throw(bad_alloc) = 0;
	virtual bool removeAction(const T* elem) = 0;	
private:
	int numberOfElements;
	//we chose to do those private because we don't want to have constructor as a "real" class which one can
	//copy and assign into
	Container_t(const Container_t& c);
	Container_t& operator=(const Container_t& c);
};

//Container temolate class implementation
template<class T> Container_t<T>::Container_t() : numberOfElements(0){
}

template<class T> Container_t<T>::~Container_t(){
	//empty implementation for destructor
}

template<class T> Container_t<T>::Container_t(const Container_t<T> &c){	
	//empty implementation for copy constructor
}

template<class T> Container_t<T>& Container_t<T>::operator =(const Container_t<T> &c){
	//implementation for assignement operator
	if(this != &c){
		removeAll();
		
	}
	return *this;
	return *this;
}

template<class T> int Container_t<T>::count() const{
	return numberOfElements;
}

//Finds the first element with value val
template<class T> T* Container_t<T>::find(T val){
	T* elm = 0;
	reset();
	while((elm = next()) != 0){
		if(*elm == val){
			return elm;
		}
	}
	return 0;
}

template<class T> bool Container_t<T>::insert(const T *elem)throw(exception){
	try{
		bool res = append(elem,count()-1);
		return res;
	}catch(exception& e){
		throw;
	}
	 
}

template<class T> bool Container_t<T>::append(const T *elem,const int index) throw(exception){
	bool bRes;
	if(index+1 < 0 || index > count()-1){
		throw range_error("Index out of bounds");		
	}
	try{
		bRes = appendAction(elem,index);
	}catch(bad_alloc& e){
		throw;
	}
	if(bRes){
		++numberOfElements;
	}
	return bRes;
}

template<class T> bool Container_t<T>::prepend(const T *elem,const int index)throw(exception){
	if(index >= 1 && index <= count()){
		bool res = 0;
		try{
			res=append(elem,index-1);
		}catch(exception& e){
			throw e;
		}	
		return res;
	}	
	throw range_error("Index out of bounds");
	
}

template<class T> T* Container_t<T>::remove(T val){
	T* elm = find(val);
	if(elm != 0){
		bool bRes = removeAction(elm);
		if(bRes){
			--numberOfElements;
			reset();
		}		
		return elm;
	}	
	return 0;
}

template<class T> bool Container_t<T>::removeAll(){
	T* elm = 0;
	reset();
	bool bRes = true;
	while((elm = next()) != 0){
		bRes &= removeAction(elm);
		--numberOfElements;
		//start from the begining again
		reset();
	}
	return bRes;
}

template<class T> bool Container_t<T>::removeAndDelete(T val){
	T* elm = remove(val);
	if(elm != 0){
		delete elm;
		elm = 0;
	}
	return false;
}

template<class T> bool Container_t<T>::removeAndDeleteAll(){
	T* elm = 0;
	reset();
	bool bRes = true;
	bool bElementRes = false;	
	while((elm = next()) != 0){
		bElementRes = removeAction(elm);
		if(bElementRes){
			delete elm;
			elm = 0;
			--numberOfElements;
		}
		bRes &= bElementRes;	
		//Invalidation
		reset();
	}
	
	return bRes;
}

template<class T> void Container_t<T>::print(){
	T* elm = 0;
	reset();
	while((elm = next()) != 0){
		cout << *elm << ",";
	}
	cout << endl;
}

#endif